package com.fast.admin.utils;

import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch._types.aggregations.*;
import co.elastic.clients.elasticsearch._types.mapping.Property;
import co.elastic.clients.elasticsearch._types.query_dsl.MatchAllQuery;
import co.elastic.clients.elasticsearch.core.*;
import co.elastic.clients.elasticsearch.core.search.Hit;
import co.elastic.clients.elasticsearch.core.search.HitsMetadata;
import co.elastic.clients.elasticsearch.indices.CreateIndexResponse;
import co.elastic.clients.elasticsearch.indices.DeleteIndexResponse;
import co.elastic.clients.transport.endpoints.BooleanResponse;
import com.fast.common.db.mapper.po.User;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author : TWL
 * @createTime : 2024/10/7 13:06
 */
@Slf4j
@Component
public class EsUtils {

    @Autowired
    private ElasticsearchClient client;

    /**
     * 判断索引是否存在
     *
     * @param indexName
     * @return
     * @throws IOException
     */
    public boolean hasIndex(String indexName) throws IOException {
        BooleanResponse exists = client.indices().exists(d -> d.index(indexName));
        return exists.value();
    }

    /**
     * 删除索引
     *
     * @param indexName
     * @throws IOException
     */
    public boolean deleteIndex(String indexName) throws IOException {
        DeleteIndexResponse response = client.indices().delete(d -> d.index(indexName));
        return true;
    }

    /**
     * 创建索引
     *
     * @param indexName
     * @return
     * @throws IOException
     */
    public boolean createIndex(String indexName) {
        try {
            CreateIndexResponse indexResponse = client.indices().create(c -> c.index(indexName));
        } catch (IOException e) {
            log.error("索引创建失败：{}", e.getMessage());
            throw new RuntimeException("创建索引失败");
        }
        return true;
    }

    /**
     * 创建索引，不允许外部直接调用
     *
     * @param indexName
     * @param mapping
     * @throws IOException
     */
    private boolean createIndex(String indexName, Map<String, Property> mapping) throws IOException {
        CreateIndexResponse createIndexResponse = client.indices().create(c -> {
            c.index(indexName).mappings(mappings -> mappings.properties(mapping));
            return c;
        });
        return createIndexResponse.acknowledged();
    }


    /**
     * 重新创建索引,如果已存在先删除
     *
     * @param indexName
     * @param mapping
     */
    public void reCreateIndex(String indexName, Map<String, Property> mapping) {
        try {
            if (this.hasIndex(indexName)) {
                this.deleteIndex(indexName);
            }
        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException("删除索引失败");
        }

        try {
            this.createIndex(indexName, mapping);
        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException("重新创建索引失败");
        }
    }


    /**
     * 新增数据
     *
     * @param indexName
     * @throws IOException
     */
    public boolean insertDocument(String indexName, Object obj, String id) {
        try {
            IndexResponse indexResponse = client.index(i -> i
                    .index(indexName)
                    .id(id)
                    .document(obj));
            return true;
        } catch (IOException e) {
            log.error("数据插入ES异常：{}", e.getMessage());
            throw new RuntimeException("ES新增数据失败");
        }
    }

    /**
     * 查询数据
     *
     * @param indexName
     * @param id
     * @return
     */
    public GetResponse<User> searchDocument(String indexName, String id) {

        try {
            GetResponse<User> getResponse = client.get(g -> g
                            .index(indexName)
                            .id(id)
                    , User.class
            );
            return getResponse;
        } catch (IOException e) {
            log.error("查询ES异常：{}", e.getMessage());
            throw new RuntimeException("查询ES数据失败");
        }
    }
    /**
     * 查询所有数据
     *
     * @return
     */
    public List<User> searchDocumentAll(String indexNmae) {

        try {
            // 创建一个SearchRequest来执行全量查询
            SearchRequest searchRequest = new SearchRequest.Builder()
                    .index(indexNmae) // 替换为你的索引名称
                    .build();

            // 执行搜索请求
            SearchResponse<User> searchResponse = client.search(searchRequest, User.class);

            // 获取搜索结果
            HitsMetadata<User> hits = searchResponse.hits();

            List<User> users = new ArrayList<>();

            // 打印结果
            for (Hit<User> hit : hits.hits()) {
                User user = hit.source();

                users.add(user);
            }

            return users;
        } catch (IOException e) {
            log.error("查询ES异常：{}", e.getMessage());
            throw new RuntimeException("查询ES数据失败");
        }
    }

    //查询总数
    public Integer count(String indexName) {
        try {
            CountRequest searchRequest = new CountRequest.Builder()
                    .index(indexName) // 替换为你的索引名称
                    .build();
            CountResponse count = client.count(searchRequest);
            return Math.toIntExact(count.count());
        }catch (Exception e){
            System.out.println(e.getMessage());
        }
        return null;
    }

        /**
         * 查询数据
         *
         * @param indexName
         * @return
         */
    public Map<String,Integer> search(String indexName) {

        try {

            // 创建一个ValueCountAggregation来统计id的数量
            Aggregation idAggregation = Aggregation.of(s -> s.valueCount(ValueCountAggregation.of(v -> v.field("id"))));
            Aggregation idAggregations = Aggregation.of(s -> s.cardinality(CardinalityAggregation.of(v -> v.field("id").precisionThreshold(4000))));
            Aggregation trams=Aggregation.of(s->s.terms(a->a.field("id").size(10000000)));

            // 将id聚合添加到搜索请求中
            SearchRequest searchRequest = new SearchRequest.Builder()
                    .index(indexName)
                    .aggregations("idCount", idAggregation)
                    .aggregations("ids", idAggregations)
                    .aggregations("trams",trams)
                    .build();

            // 执行搜索请求
            SearchResponse<Void> searchResponse = client.search(searchRequest, Void.class);


            // 获取id聚合的结果
            ValueCountAggregate valueCount = searchResponse.aggregations().get("idCount").valueCount();
            double totalCount = valueCount.value(); // 获取id的数量
            double ids = searchResponse.aggregations().get("ids").cardinality().value();
            double tram = searchResponse.aggregations().get("trams").lterms().buckets().array().size();

            Map<String,Integer> map = new HashMap<>();
            map.put("count", (int) totalCount);
            map.put("idcount", (int) ids);
            map.put("trams", (int) tram);

            return map;
        } catch (IOException e) {
            log.error("查询ES异常：{}", e.getMessage());
            throw new RuntimeException("查询ES数据失败");
        }

    }
    public Map<String,Integer> searchjq(String indexName) {

        try {

                      // 将id聚合添加到搜索请求中
            SearchRequest searchRequest = new SearchRequest.Builder()
                    .index(indexName)
                    .query(q -> q.matchAll(MatchAllQuery.of(m -> m)))
                    .collapse(c -> c.field("id"))
                    .build();

            // 执行搜索请求
            SearchResponse<Void> searchResponse = client.search(searchRequest, Void.class);

            Map<String,Integer> map = new HashMap<>();


            return map;
        } catch (IOException e) {
            log.error("查询ES异常：{}", e.getMessage());
            throw new RuntimeException("查询ES数据失败");
        }

    }

    /**
     * 删除数据
     *
     * @param indexName
     * @param id
     * @return
     */
    public boolean deleteDocument(String indexName, String id) {
        try {
            DeleteResponse deleteResponse = client.delete(d -> d
                    .index(indexName)
                    .id(id)
            );
        } catch (IOException e) {
            log.error("删除Es数据异常：{}", e.getMessage());
            throw new RuntimeException("数据删除失败");
        }
        return true;
    }

}

